The basics of pillow¶

create new image by import¶

In [1]:
from IPython.display import display
from PIL import Image

img = Image.open("fruits.png")
img # img.show() / show the picture
Out[1]:
No description has been provided for this image

alternative way to import an image

In [2]:
with Image.open("fruits.png") as img:
    display(img) # img.show()
No description has been provided for this image

create a new image from scratch¶

In [3]:
new_img = Image.new(mode="RGBA",size=(300, 200))
new_img
Out[3]:
No description has been provided for this image

saving the picture

In [4]:
# img.save("test.png")

image information¶

In [5]:
img.size
Out[5]:
(300, 200)
In [6]:
img.filename
Out[6]:
'fruits.png'
In [7]:
img.format
Out[7]:
'PNG'
In [8]:
img.format_description
Out[8]:
'Portable network graphics'

Basic manipulation¶

Rotate¶

In [9]:
img_rotate = img.rotate(60)
img_rotate
Out[9]:
No description has been provided for this image
In [10]:
img_rotate = img.rotate(60,expand=True,fillcolor= (0, 128, 0))
img_rotate
Out[10]:
No description has been provided for this image
In [11]:
from PIL import ImageColor

ImageColor.getcolor("Green","RGB")
Out[11]:
(0, 128, 0)
In [12]:
img_rotate = img.rotate(60,expand=True,
    fillcolor= ImageColor.getcolor("Green","RGB")) # (0, 128, 0)
img_rotate
Out[12]:
No description has been provided for this image

Crop¶

Crop(( left_X , top_Y , right_X , bottom_Y ))

In [13]:
img_crop = img.crop((0,0,300,100))
img_crop
Out[13]:
No description has been provided for this image
In [14]:
img_crop = img.crop((200,80,260,150))
img_crop
Out[14]:
No description has been provided for this image

flipping the image / transpose the image¶

In [15]:
img_flip_horizontal = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
display(img) # original pitcure
img_flip_horizontal
No description has been provided for this image
Out[15]:
No description has been provided for this image
In [16]:
img_flip_vertical = img.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
display(img) # original picture
img_flip_vertical
No description has been provided for this image
Out[16]:
No description has been provided for this image
In [17]:
img_flip_rotate_90 = img.transpose(Image.Transpose.ROTATE_90)
display(img_flip_rotate_90)

img_flip_rotate_180 = img.transpose(Image.Transpose.ROTATE_180)
display(img_flip_rotate_180)

img_flip_rotate_270 = img.transpose(Image.Transpose.ROTATE_270)
display(img_flip_rotate_270)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [18]:
img_flip_transpose = img.transpose(Image.Transpose.TRANSPOSE)
display(img_flip_transpose)

img_flip_transverse = img.transpose(Image.Transpose.TRANSVERSE)
display(img_flip_transverse)
No description has been provided for this image
No description has been provided for this image

Resize¶

In [19]:
width = img.size[0] # 480
height = img.size[1] # 320

img_resize = img.resize((width*2 , height*2))
img_resize
Out[19]:
No description has been provided for this image

Filters and Enhancements¶

Enhancement¶

Color

In [20]:
from PIL import ImageEnhance

img_color = ImageEnhance.Color(img)

display(img_color.enhance(-1))
display(img_color.enhance(0))
display(img_color.enhance(0.5))
display(img_color.enhance(1))
display(img_color.enhance(3))
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Contrast

In [21]:
img_contrast = ImageEnhance.Contrast(img)

display(img_contrast.enhance(-1))
display(img_contrast.enhance(0))
display(img_contrast.enhance(0.5))
display(img_contrast.enhance(2))
display(img_contrast.enhance(10))
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Brightness

In [22]:
img_brightness = ImageEnhance.Brightness(img)

display(img_brightness.enhance(0))
display(img_brightness.enhance(1))
display(img_brightness.enhance(2))
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Sharpness

In [23]:
img_sharpness = ImageEnhance.Sharpness(img)

display(img_sharpness.enhance(-2))
display(img_sharpness.enhance(1))
display(img_sharpness.enhance(5))
display(img_sharpness.enhance(9))
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Filter¶

BoxBlur

In [24]:
from PIL import ImageFilter

img_boxblur = img.filter(ImageFilter.BoxBlur(12))
img_boxblur
Out[24]:
No description has been provided for this image

GaussianBlur

In [25]:
img_gaussblur = img.filter(ImageFilter.GaussianBlur(3))
img_gaussblur
Out[25]:
No description has been provided for this image

UnsharpMask

In [26]:
img_unsharp = img.filter(ImageFilter.UnsharpMask(8))
img_unsharp
Out[26]:
No description has been provided for this image

Blur

In [27]:
img_blur = img.filter(ImageFilter.BLUR)
img_blur
Out[27]:
No description has been provided for this image

Contour

In [28]:
img_contour = img.filter(ImageFilter.CONTOUR)
img_contour
Out[28]:
No description has been provided for this image

DETAIL

In [29]:
img_detail = img.filter(ImageFilter.DETAIL)
display(img) # original picture
img_detail
No description has been provided for this image
Out[29]:
No description has been provided for this image

Edge Enchance

In [30]:
img_edge_enchance = img.filter(ImageFilter.EDGE_ENHANCE)
img_edge_enchance
Out[30]:
No description has been provided for this image

Edge Enchance More

In [31]:
img_edge_enchance_more = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
img_edge_enchance_more
Out[31]:
No description has been provided for this image

Find Edge

In [32]:
img_find_edge = img.filter(ImageFilter.FIND_EDGES)
img_find_edge
Out[32]:
No description has been provided for this image

Emboss

In [33]:
img_emboss = img.filter(ImageFilter.EMBOSS)
img_emboss
Out[33]:
No description has been provided for this image

Sharpen

In [34]:
img_sharpen = img.filter(ImageFilter.SHARPEN)
img_sharpen
Out[34]:
No description has been provided for this image

Smooth

In [35]:
img_smooth = img.filter(ImageFilter.SMOOTH)
img_smooth
Out[35]:
No description has been provided for this image

Smooth More

In [36]:
img_smooth_more = img.filter(ImageFilter.SMOOTH_MORE)
img_smooth_more
Out[36]:
No description has been provided for this image

Min Filter

In [37]:
img_min_filter = img.filter(ImageFilter.MinFilter(5))
img_min_filter
Out[37]:
No description has been provided for this image

Median Filter

In [38]:
img_median_filter = img.filter(ImageFilter.MedianFilter(5))
img_median_filter
Out[38]:
No description has been provided for this image

Max Filter

In [39]:
img_max_filter = img.filter(ImageFilter.MaxFilter(5))
img_max_filter
Out[39]:
No description has been provided for this image

Mode Filter

In [40]:
img_mode_filter = img.filter(ImageFilter.ModeFilter(5))
img_mode_filter
Out[40]:
No description has been provided for this image

Colors in Pillow¶

Analysing picture information¶

In [41]:
display(img.crop((0,0,1,1)).resize((30,30)))

img.getpixel((0,0))
# ( R , G , B )
No description has been provided for this image
Out[41]:
(245, 194, 166)
In [117]:
img.getcolors(maxcolors= img.size[0]*img.size[1])[0:10]

# showing every colors and number of used it
# ( number_of_use, ( R , G , B ))
Out[117]:
[(17, (255, 255, 255)),
 (1, (1, 0, 0)),
 (4, (254, 255, 255)),
 (1, (252, 255, 255)),
 (1, (251, 255, 251)),
 (7, (250, 255, 255)),
 (6, (249, 255, 255)),
 (4, (248, 255, 255)),
 (5, (251, 255, 255)),
 (2, (246, 255, 254))]
In [43]:
img.mode
Out[43]:
'RGB'
In [44]:
img.getbands()
Out[44]:
('R', 'G', 'B')
In [45]:
img.info
Out[45]:
{'dpi': (72.009, 72.009),
 'xmp': b'<?xpacket begin="\xef\xbb\xbf" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 9.1-c003 79.9690a87, 2025/03/06-19:12:03        "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmp:CreatorTool="Adobe Photoshop 26.8 (Windows)" xmp:CreateDate="2025-07-24T11:53:08+03:30" xmp:ModifyDate="2025-07-25T09:19:21+03:30" xmp:MetadataDate="2025-07-25T09:19:21+03:30" dc:format="image/png" photoshop:ColorMode="3" xmpMM:InstanceID="xmp.iid:f0f5ae2e-565e-964d-baee-d2480d24f523" xmpMM:DocumentID="xmp.did:eac1155c-5760-5b4c-864e-4987de78e248" xmpMM:OriginalDocumentID="xmp.did:eac1155c-5760-5b4c-864e-4987de78e248"> <xmpMM:History> <rdf:Seq> <rdf:li stEvt:action="created" stEvt:instanceID="xmp.iid:eac1155c-5760-5b4c-864e-4987de78e248" stEvt:when="2025-07-24T11:53:08+03:30" stEvt:softwareAgent="Adobe Photoshop 26.8 (Windows)"/> <rdf:li stEvt:action="saved" stEvt:instanceID="xmp.iid:be8255f3-87b7-7e47-8ffe-9224bc1851ae" stEvt:when="2025-07-24T13:12:18+03:30" stEvt:softwareAgent="Adobe Photoshop 26.8 (Windows)" stEvt:changed="/"/> <rdf:li stEvt:action="saved" stEvt:instanceID="xmp.iid:f0f5ae2e-565e-964d-baee-d2480d24f523" stEvt:when="2025-07-25T09:19:21+03:30" stEvt:softwareAgent="Adobe Photoshop 26.8 (Windows)" stEvt:changed="/"/> </rdf:Seq> </xmpMM:History> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?>',
 'XML:com.adobe.xmp': '<?xpacket begin="\ufeff" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 9.1-c003 79.9690a87, 2025/03/06-19:12:03        "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmp:CreatorTool="Adobe Photoshop 26.8 (Windows)" xmp:CreateDate="2025-07-24T11:53:08+03:30" xmp:ModifyDate="2025-07-25T09:19:21+03:30" xmp:MetadataDate="2025-07-25T09:19:21+03:30" dc:format="image/png" photoshop:ColorMode="3" xmpMM:InstanceID="xmp.iid:f0f5ae2e-565e-964d-baee-d2480d24f523" xmpMM:DocumentID="xmp.did:eac1155c-5760-5b4c-864e-4987de78e248" xmpMM:OriginalDocumentID="xmp.did:eac1155c-5760-5b4c-864e-4987de78e248"> <xmpMM:History> <rdf:Seq> <rdf:li stEvt:action="created" stEvt:instanceID="xmp.iid:eac1155c-5760-5b4c-864e-4987de78e248" stEvt:when="2025-07-24T11:53:08+03:30" stEvt:softwareAgent="Adobe Photoshop 26.8 (Windows)"/> <rdf:li stEvt:action="saved" stEvt:instanceID="xmp.iid:be8255f3-87b7-7e47-8ffe-9224bc1851ae" stEvt:when="2025-07-24T13:12:18+03:30" stEvt:softwareAgent="Adobe Photoshop 26.8 (Windows)" stEvt:changed="/"/> <rdf:li stEvt:action="saved" stEvt:instanceID="xmp.iid:f0f5ae2e-565e-964d-baee-d2480d24f523" stEvt:when="2025-07-25T09:19:21+03:30" stEvt:softwareAgent="Adobe Photoshop 26.8 (Windows)" stEvt:changed="/"/> </rdf:Seq> </xmpMM:History> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?>'}

channels¶

In [46]:
img.getchannel("R")
Out[46]:
No description has been provided for this image
In [47]:
img.getchannel("G")
Out[47]:
No description has been provided for this image
In [48]:
img.getchannel("B")
Out[48]:
No description has been provided for this image

numpy section

In [120]:
import numpy as np    
display(np.array(img).shape) # ( img.size[1] , img.size[0] , RGB )
np.array(img)[0][0:10]
# [[ R ] , [ G ] , [ B ]]
(200, 300, 3)
Out[120]:
array([[245, 194, 166],
       [247, 182, 152],
       [247, 202, 191],
       [223, 196,  88],
       [232, 182,   0],
       [188, 154,  60],
       [207, 192, 153],
       [227, 185,   3],
       [235, 200,   5],
       [242, 206,   0]], dtype=uint8)
In [50]:
np.array(img.getchannel('R'))
Out[50]:
array([[245, 247, 247, ..., 246, 245, 245],
       [244, 253, 231, ..., 245, 246, 247],
       [248, 250, 217, ..., 246, 244, 246],
       ...,
       [246, 247, 247, ..., 244, 244, 246],
       [247, 250, 247, ..., 245, 247, 246],
       [245, 247, 250, ..., 246, 246, 245]], shape=(200, 300), dtype=uint8)

Color converstions¶

In [51]:
img_grayscale_1bit = img.convert('1')
img_grayscale_1bit
Out[51]:
No description has been provided for this image
In [52]:
np.array(img_grayscale_1bit,dtype=int)
Out[52]:
array([[1, 1, 1, ..., 1, 1, 1],
       [1, 1, 0, ..., 1, 1, 0],
       [1, 1, 1, ..., 1, 1, 1],
       ...,
       [1, 1, 1, ..., 1, 1, 1],
       [1, 0, 1, ..., 1, 0, 1],
       [1, 1, 1, ..., 1, 1, 1]], shape=(200, 300))
In [53]:
img_grayscale_l = img.convert('L')
img_grayscale_l
Out[53]:
No description has been provided for this image
In [54]:
# np.array(img) == img.getbands() 
In [55]:
img_palette = img.convert('P')
img_palette
Out[55]:
No description has been provided for this image
In [56]:
np.array(img_palette.getpalette())
Out[56]:
array([  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
         0,   0,   0,   0,   0,   0,   0,  51,   0,   0, 102,   0,   0,
       153,   0,   0, 204,   0,   0, 255,   0,   0,   0,  51,   0,  51,
        51,   0, 102,  51,   0, 153,  51,   0, 204,  51,   0, 255,  51,
         0,   0, 102,   0,  51, 102,   0, 102, 102,   0, 153, 102,   0,
       204, 102,   0, 255, 102,   0,   0, 153,   0,  51, 153,   0, 102,
       153,   0, 153, 153,   0, 204, 153,   0, 255, 153,   0,   0, 204,
         0,  51, 204,   0, 102, 204,   0, 153, 204,   0, 204, 204,   0,
       255, 204,   0,   0, 255,   0,  51, 255,   0, 102, 255,   0, 153,
       255,   0, 204, 255,   0, 255, 255,   0,   0,   0,  51,  51,   0,
        51, 102,   0,  51, 153,   0,  51, 204,   0,  51, 255,   0,  51,
         0,  51,  51,  51,  51,  51, 102,  51,  51, 153,  51,  51, 204,
        51,  51, 255,  51,  51,   0, 102,  51,  51, 102,  51, 102, 102,
        51, 153, 102,  51, 204, 102,  51, 255, 102,  51,   0, 153,  51,
        51, 153,  51, 102, 153,  51, 153, 153,  51, 204, 153,  51, 255,
       153,  51,   0, 204,  51,  51, 204,  51, 102, 204,  51, 153, 204,
        51, 204, 204,  51, 255, 204,  51,   0, 255,  51,  51, 255,  51,
       102, 255,  51, 153, 255,  51, 204, 255,  51, 255, 255,  51,   0,
         0, 102,  51,   0, 102, 102,   0, 102, 153,   0, 102, 204,   0,
       102, 255,   0, 102,   0,  51, 102,  51,  51, 102, 102,  51, 102,
       153,  51, 102, 204,  51, 102, 255,  51, 102,   0, 102, 102,  51,
       102, 102, 102, 102, 102, 153, 102, 102, 204, 102, 102, 255, 102,
       102,   0, 153, 102,  51, 153, 102, 102, 153, 102, 153, 153, 102,
       204, 153, 102, 255, 153, 102,   0, 204, 102,  51, 204, 102, 102,
       204, 102, 153, 204, 102, 204, 204, 102, 255, 204, 102,   0, 255,
       102,  51, 255, 102, 102, 255, 102, 153, 255, 102, 204, 255, 102,
       255, 255, 102,   0,   0, 153,  51,   0, 153, 102,   0, 153, 153,
         0, 153, 204,   0, 153, 255,   0, 153,   0,  51, 153,  51,  51,
       153, 102,  51, 153, 153,  51, 153, 204,  51, 153, 255,  51, 153,
         0, 102, 153,  51, 102, 153, 102, 102, 153, 153, 102, 153, 204,
       102, 153, 255, 102, 153,   0, 153, 153,  51, 153, 153, 102, 153,
       153, 153, 153, 153, 204, 153, 153, 255, 153, 153,   0, 204, 153,
        51, 204, 153, 102, 204, 153, 153, 204, 153, 204, 204, 153, 255,
       204, 153,   0, 255, 153,  51, 255, 153, 102, 255, 153, 153, 255,
       153, 204, 255, 153, 255, 255, 153,   0,   0, 204,  51,   0, 204,
       102,   0, 204, 153,   0, 204, 204,   0, 204, 255,   0, 204,   0,
        51, 204,  51,  51, 204, 102,  51, 204, 153,  51, 204, 204,  51,
       204, 255,  51, 204,   0, 102, 204,  51, 102, 204, 102, 102, 204,
       153, 102, 204, 204, 102, 204, 255, 102, 204,   0, 153, 204,  51,
       153, 204, 102, 153, 204, 153, 153, 204, 204, 153, 204, 255, 153,
       204,   0, 204, 204,  51, 204, 204, 102, 204, 204, 153, 204, 204,
       204, 204, 204, 255, 204, 204,   0, 255, 204,  51, 255, 204, 102,
       255, 204, 153, 255, 204, 204, 255, 204, 255, 255, 204,   0,   0,
       255,  51,   0, 255, 102,   0, 255, 153,   0, 255, 204,   0, 255,
       255,   0, 255,   0,  51, 255,  51,  51, 255, 102,  51, 255, 153,
        51, 255, 204,  51, 255, 255,  51, 255,   0, 102, 255,  51, 102,
       255, 102, 102, 255, 153, 102, 255, 204, 102, 255, 255, 102, 255,
         0, 153, 255,  51, 153, 255, 102, 153, 255, 153, 153, 255, 204,
       153, 255, 255, 153, 255,   0, 204, 255,  51, 204, 255, 102, 204,
       255, 153, 204, 255, 204, 204, 255, 255, 204, 255,   0, 255, 255,
        51, 255, 255, 102, 255, 255, 153, 255, 255, 204, 255, 255, 255,
       255, 255])
In [57]:
img_palette_6 = img.convert('P',palette= Image.Palette.ADAPTIVE,colors=6)
img_palette_6
Out[57]:
No description has been provided for this image
In [58]:
new_palette = [ x // 2 for x in img_palette_6.getpalette()]
img_palette_6.putpalette(new_palette)
img_palette_6
Out[58]:
No description has been provided for this image
In [59]:
Image.MODES
Out[59]:
['1',
 'CMYK',
 'F',
 'HSV',
 'I',
 'I;16',
 'I;16B',
 'I;16L',
 'I;16N',
 'L',
 'LA',
 'La',
 'LAB',
 'P',
 'PA',
 'RGB',
 'RGBA',
 'RGBa',
 'RGBX',
 'YCbCr']

put pixel

In [60]:
img_putpixel = img.crop((0,0,40,40))

for num in range(1,18):
    img_putpixel.putpixel((20,20 + num ),(255,0,0))
    img_putpixel.putpixel((21,20 + num ),(255,0,0))
    img_putpixel.putpixel((22,20 + num ),(255,0,0))

img_putpixel.putpixel((21,26),(0,0,255))

img_putpixel.resize((200,200))
Out[60]:
No description has been provided for this image
In [61]:
new_img = img.copy()

for x in range(new_img.size[0]):
    for y in range(new_img.size[1]):
        if new_img.getpixel((x,y))[0] > 240:
            new_img.putpixel((x,y),(0,0,255))
new_img
Out[61]:
No description has been provided for this image

ImageOps works kinda like a filter but it can do more¶

color change¶

In [62]:
from PIL import ImageOps

ImageOps.autocontrast(img,cutoff= 4)
Out[62]:
No description has been provided for this image
In [63]:
ImageOps.invert(img)
Out[63]:
No description has been provided for this image
In [64]:
ImageOps.solarize(img,threshold=190)
Out[64]:
No description has been provided for this image
In [65]:
ImageOps.posterize(img,bits=2)
Out[65]:
No description has been provided for this image
In [66]:
ImageOps.grayscale(img)
Out[66]:
No description has been provided for this image
In [67]:
ImageOps.equalize(img)
Out[67]:
No description has been provided for this image
In [68]:
ImageOps.colorize(img.convert('L'),black="yellow",white='red',blackpoint=50)
Out[68]:
No description has been provided for this image

dimension changes¶

In [69]:
ImageOps.mirror(img) # img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
Out[69]:
No description has been provided for this image
In [70]:
ImageOps.flip(img) # img.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
Out[70]:
No description has been provided for this image
In [71]:
ImageOps.scale(img,factor= 0.4) 
# img.resize((int(img.size[0]*0.4),int(img.size[1]*0.4)))
Out[71]:
No description has been provided for this image
In [72]:
ImageOps.contain(img,size=(200,200))
Out[72]:
No description has been provided for this image

Adding and removing¶

In [73]:
ImageOps.expand(img,border=(25,6),fill='green')
Out[73]:
No description has been provided for this image
In [74]:
ImageOps.pad(img ,size=(400,200),color="red")
Out[74]:
No description has been provided for this image
In [75]:
ImageOps.fit(img,size=(100,200))
Out[75]:
No description has been provided for this image
In [76]:
ImageOps.crop(img,border=60)
Out[76]:
No description has been provided for this image

diformer¶

In [77]:
class Diformer:
    def getmesh(self,img : Image):
        width , height = img.size
        soures_shape = (0,0              # ┌─
                        ,0,height        # └─        
                        ,width,height    #  ─┘
                        ,width,0)        # └─

        target_rect = (0,0,width //2,height)
        return [(target_rect,soures_shape)]

ImageOps.deform(img,Diformer())
Out[77]:
No description has been provided for this image
In [78]:
class Diformer:
    def getmesh(self,img : Image):
        width , height = img.size
        soures_shape = (0,0                     # ┌─
                        ,0,height               # └─        
                        ,width - 200,height     #  ─┘
                        ,width,0)               # └─

        target_rect = (0,0,width //2,height)
        return [(target_rect,soures_shape)]

ImageOps.deform(img,Diformer())
Out[78]:
No description has been provided for this image
In [79]:
class Diformer:
    def getmesh(self,img : Image):
        width , height = img.size
        # (0,0) ┌─
        # (w,h)   ─┘
        left = (0,0, width//2 ,height),(0,0,0,height,width//2,height,width//2,0)
        right = (width//2 ,0,width,height),(width//2,0,width//2,height,0,height,0,0)

        return [left,right]

ImageOps.deform(img,Diformer())
Out[79]:
No description has been provided for this image
In [80]:
class Diformer:
    def getmesh(self,img : Image):
        width , height = img.size
        # (0,0) ┌─
        # (w,h)   ─┘
        left = (0,0, width//2 ,height),(0,0,0,height,width//2,height,width//2,0)
        right = (width//2 ,0,width,height),(width//2,height,width//2,0,width,0,width,height)

        return [left,right]
    
ImageOps.deform(img,Diformer())
Out[80]:
No description has been provided for this image
In [81]:
class Diformer:
    def transform(self, x , y):
        import math
        y = y + 30*math.sin(x/40)
        return x , y
    
    def transform_rectangle(self,x0,y0,x1,y1):
        return ( *self.transform(x0,y0),
                 *self.transform(x0,y1),
                 *self.transform(x1,y1),
                 *self.transform(x1,y0),)
    
    def getmesh(self,img : Image):
        width , height = img.size
        gridspace = 20
        target_grid = []
        for x in range(0,width,gridspace):
            for y in range(0,height,gridspace):
                target_grid.append((x,y,x+gridspace,y+gridspace))
        source_grid = [ self.transform_rectangle(*rect) for rect in target_grid]

        return [ t for t in zip(target_grid,source_grid)]
    
ImageOps.deform(img,Diformer())
Out[81]:
No description has been provided for this image

Drawing shapes¶

In [82]:
from PIL import ImageDraw

new_img = img.copy()

draw = ImageDraw.Draw(new_img)
draw.rectangle((30,30,100,180),width=3)

new_img
Out[82]:
No description has been provided for this image
In [83]:
draw.rectangle((30,30,100,180),width=3 , outline='yellow',fill='green')

new_img
Out[83]:
No description has been provided for this image
In [84]:
draw.ellipse((33,33,97,176),width=0 ,fill='purple')

new_img
Out[84]:
No description has been provided for this image
In [85]:
draw.polygon(((120,40),(176,20),(200,56),(176,70)),width=4,fill='blue',outline="white")

new_img
Out[85]:
No description has been provided for this image
In [86]:
draw.line(((170,180),(289,160),(250,40)),fill="black",width=5,joint='curve')

new_img
Out[86]:
No description has been provided for this image
In [87]:
draw.arc((170,100,220,150),start=20,end=200,width=5,fill='yellow')

new_img
Out[87]:
No description has been provided for this image
In [88]:
draw.chord((170,100,220,150),start=20,end=200,width=5,fill='yellow')

new_img
Out[88]:
No description has been provided for this image
In [89]:
draw.pieslice((170,100,220,150),start=40,end=80,width=5,fill='green')

new_img
Out[89]:
No description has been provided for this image
In [90]:
from PIL import ImageFont

font = ImageFont.truetype(font='arial',size=20)
draw.text((40,50),'fruits',font=font,fill='red')

new_img
Out[90]:
No description has been provided for this image

Combining images¶

merging images with Image.mehods( )¶

In [91]:
picture = Image.open('picture.jpg')
picture
Out[91]:
No description has been provided for this image
In [92]:
# both images need same size and mode
Image.blend(img,picture,0.6)
Out[92]:
No description has been provided for this image
In [93]:
Image.composite(img,picture,mask= Image.new('L',img.size,100))
Out[93]:
No description has been provided for this image

image paste¶

In [94]:
python = Image.open("python.png")
python
Out[94]:
No description has been provided for this image
In [95]:
new_img = img.copy()

new_img.paste(python,(100,50),mask=python)
new_img
Out[95]:
No description has been provided for this image

channel operations¶

In [96]:
from PIL import ImageChops

ImageChops.overlay(img,picture)
Out[96]:
No description has been provided for this image
In [97]:
ImageChops.darker(img,picture)
Out[97]:
No description has been provided for this image
In [98]:
ImageChops.lighter(img,picture)
Out[98]:
No description has been provided for this image
In [99]:
ImageChops.soft_light(img,picture)
Out[99]:
No description has been provided for this image
In [100]:
ImageChops.hard_light(img,picture)
Out[100]:
No description has been provided for this image
In [101]:
ImageChops.difference(img,picture)
Out[101]:
No description has been provided for this image
In [102]:
ImageChops.add_modulo(img,picture)
Out[102]:
No description has been provided for this image
In [103]:
ImageChops.screen(img,picture)
Out[103]:
No description has been provided for this image
In [104]:
ImageChops.multiply(img,picture)
Out[104]:
No description has been provided for this image

more complex channel operations¶

In [105]:
ImageChops.add(img,picture,scale=3,offset=100)
Out[105]:
No description has been provided for this image
In [106]:
ImageChops.add(img,picture,scale=2,offset=20)
Out[106]:
No description has been provided for this image
In [107]:
ImageChops.subtract(img,picture,scale=2,offset=100)
Out[107]:
No description has been provided for this image

logical¶

In [108]:
ImageChops.logical_and(img.convert('1'),picture.convert('1'))
Out[108]:
No description has been provided for this image
In [109]:
ImageChops.logical_or(img.convert('1'),picture.convert('1'))
Out[109]:
No description has been provided for this image
In [110]:
ImageChops.logical_xor(img.convert('1'),picture.convert('1'))
Out[110]:
No description has been provided for this image

masking¶

In [111]:
mask = Image.open("mask.png")
Image.open("mask.png").convert('L')
Out[111]:
No description has been provided for this image
In [112]:
img_masked_alpha = Image.alpha_composite(img.convert("RGBA"),mask)
img_masked_alpha
Out[112]:
No description has been provided for this image
In [113]:
img_masked = Image.composite(img,picture,mask=mask)
img_masked
Out[113]:
No description has been provided for this image
In [114]:
img_masked = Image.composite(img,picture,mask=mask.convert('L'))
img_masked
Out[114]:
No description has been provided for this image